"""
多路复用（select、poll和epoll）

通过非阻塞IO实现HTTP请求

核心知识：
    1.epoll并不代表一定比select好
        1.1在并发高的情况下，连接活跃度不是很高，epoll比select好（如：web网站）
        1.2并发性不高，同时连接很活跃，select比epoll好（如：游戏）
"""

import socket
import time
from urllib.parse import urlparse


def get_url(url):
    # 通过Socket请求html
    url = urlparse(url)
    host = url.netloc
    path = url.path
    if not path:
        path = "/"

    # 建立Socket连接
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 启用非阻塞
    client.setblocking(False)

    # connect阻塞不会消耗CPU
    try:
        client.connect((host, 80))
    except BlockingIOError as e:
        pass

    # 不停地询问连接是否创建好，需要while循环不停地去检查状态（会消耗CPU）
    # 做计算任务或者再次发起其他的连接请求（适合使用非阻塞IO）

    while True:
        try:
            client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8"))
            break
        except OSError as e:
            pass

    data = b""
    while True:
        try:
            d = client.recv(1024)
        except BlockingIOError as e:
            continue

        if d:
            data += d
        else:
            break

    data = data.decode("utf8")
    # 通过两个回车换行符去掉头部信息
    html_data = data.split("\r\n\r\n")[1]
    print(html_data)

    client.close()


def use_socket_http():
    start_time = time.time()
    for url in range(1, 10):
        url = "http://shop.projectsedu.com/goods/{}/".format(url)
        get_url(url)
    print(time.time() - start_time)


if __name__ == '__main__':
    use_socket_http()
